using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.IsolatedStorage;

using FlatRedBall;
using FlatRedBall.Graphics;
using FlatRedBall.Graphics.Animation;
using FlatRedBall.Math.Geometry;
using FlatRedBall.Input;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Media;

using Xzipit.GameObjects;
using Xzipit.Interfaces;

namespace Xzipit.Utilities
{
    public static class LevelManager
    {
        private static List<Obstacle> _obstacles;
        private static List<Vector3> _track;
        private static Zipper _zipper;

        private static Sprite _background;
        private static Song _bgMusic;

        private static int _pinNum;
        private static List<List<double>> _targetTimes;

        private static string _levelName;
        private static string _levelDesc;

        public static bool IsTutorial;

        public static bool Restarting
        {
            get;
            set;
        }

        public static Song BgMusic
        {
            get { return _bgMusic; }
        }

        public static List<Obstacle> Obstacles
        {
            get { return _obstacles; }
            set { _obstacles = value; }
        }

        public static List<Vector3> Track
        {
            get { return _track; }
            set { _track = value; }
        }

        public static List<List<double>> TargetTimes
        {
            get { return _targetTimes; }
            set { _targetTimes = value; }
        }

        public static Zipper Zipper
        {
            get { return _zipper; }
        }

        public static Sprite Background
        {
            get { return _background; }
        }

        public static string LevelName
        {
            get { return _levelName; }
        }

        public static string LevelDesc
        {
            get { return _levelDesc; }
        }

        public static int PinNumber
        {
            get { return _pinNum; }
        }

        public static void Initialize()
        {
            _obstacles = new List<GameObjects.Obstacle>();
            _track = new List<Vector3>();
            _bgMusic = FlatRedBallServices.Load<Song>(@"Content/Sound/theme", "Global");
            Microsoft.Xna.Framework.Media.MediaPlayer.IsRepeating = true;
            LoadAllTargetTimes();
            Restarting = false;
        }

        public static void LoadLevel()
        {
            IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
            string path = GetLevelPath();

            StreamReader read = new StreamReader(TitleContainer.OpenStream(path));

            _obstacles = new List<Obstacle>();
            _track = new List<Vector3>();

            while (!read.EndOfStream)
            {
                string[] line = read.ReadLine().Split(' ');
                if (line[0].Equals("bg"))
                {
                    SetBG(int.Parse(line[1]));
                }
                else if (line[0].Equals("n"))
                {
                    _track.Add(new Vector3(float.Parse(line[1]), float.Parse(line[2]), 0.0f));
                }
                else if (line[0].Equals("b"))
                {
                    Button b = new Button("Global", float.Parse(line[1]), 
                        float.Parse(line[2]), int.Parse(line[3]), float.Parse(line[4]), 
                        float.Parse(line[5]));
                    _obstacles.Add(b);
                    ActionManager.AddTappableObject(b);
                    ActionManager.AddPullableObject(b);
                }
                else if (line[0].Equals("v"))
                {
                    _obstacles.Add(new Velcro("Global", float.Parse(line[1]), 
                        float.Parse(line[2]), int.Parse(line[3]), float.Parse(line[4])));
                }
                else if (line[0].Equals("o"))
                {
                    _obstacles.Add(new Necklace("Global", float.Parse(line[1]), 
                        float.Parse(line[2]), new Vector3(float.Parse(line[4]), 
                        float.Parse(line[5]), 0.0f)));                    
                }
                else if (line[0].Equals("k"))
                {
                    Buckle b = new Buckle("Global", float.Parse(line[1]), 
                        float.Parse(line[2]), int.Parse(line[3]), float.Parse(line[4]),
                        int.Parse(line[5]));
                    _obstacles.Add(b);
                    ActionManager.AddPinchableObject(b);
                }
                else if (line[0].Equals("tut"))
                {
                    if (line[1].Equals("y"))
                        IsTutorial = true;
                    else
                        IsTutorial = false;
                }
            }

            _zipper = new Zipper("Global", _track);

            read.Close();

        }

        #region Save Data
        public static void CreateInfo()
        {
            
            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();

            //create new file
            using (StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream("save.txt", 
                    FileMode.Create, FileAccess.Write, myIsolatedStorage)))
            {
                for (int i = 1; i <= GameProperties.TOTAL_LEVELS; i++) {
                    writeFile.WriteLine(i + " -");
                }
                writeFile.Flush();
                writeFile.Close();
            }

            myIsolatedStorage.Dispose();
        }

        /// <summary>
        /// Reads the save data record of all levels and returns the raw text.
        /// </summary>
        /// <returns>The raw text from the save file.</returns>
        public static string ReadInfo()
        {
            string text;

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
            if (!myIsolatedStorage.FileExists("save.txt"))
            {
                CreateInfo();
            }
            IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile("save.txt", FileMode.Open, FileAccess.Read);
            using (StreamReader reader = new StreamReader(fileStream))
            {
                text = reader.ReadToEnd();
                reader.Close();
            }

            myIsolatedStorage.Dispose();

            return text;
        }

        public static void SaveInfo(int levelNum, double levelTime)
        {
            string writeString = "";
            string[] split;
            string finalString = "";

            writeString = ReadInfo();
            split = writeString.Split('\n');

            foreach (string s in split)
            {
                if (!s.Equals(""))
                {
                    string temp = s.Trim();
                    double time;

                    // Get the time from the Save File. Handles Default - Time.
                    if (s.Split(' ')[1].Trim().Equals("-"))
                        time = Double.MaxValue;
                    else
                        time = double.Parse(s.Split(' ')[1]);

                    if (int.Parse(s.Split(' ')[0]) == levelNum && time > levelTime)
                    {
                        temp = levelNum + " " + levelTime;
                    }
                    finalString += temp + "\n";
                }
            }

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();

            //create new file
            using (StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream("save.txt", 
                    FileMode.Create, FileAccess.Write, myIsolatedStorage)))
            {
                writeFile.Write(finalString);
                writeFile.Flush();
                writeFile.Close();
            }

            myIsolatedStorage.Dispose();
        }

        public static void WipeData()
        {
            string finalString = "";

            for (int i = 1; i <= GameProperties.TOTAL_LEVELS; i++)
            {
                string temp = i + " -\n";
                finalString += temp;
            }

            IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();

            //create new file
            using (StreamWriter writeFile = new StreamWriter(new IsolatedStorageFileStream("save.txt",
                    FileMode.Create, FileAccess.Write, myIsolatedStorage)))
            {
                writeFile.Write(finalString);
                writeFile.Flush();
                writeFile.Close();
            }

            myIsolatedStorage.Dispose();

        }

        /// <summary>
        /// Gets the level description, the title and the pin of an individual level.
        /// </summary>
        public static void LoadInfo()
        {
            string path = GetLevelPath();

            StreamReader read = new StreamReader(TitleContainer.OpenStream(path));

            while (!read.EndOfStream)
            {
                string line = read.ReadLine();
                string[] split = line.Split(' ');
                if (split[0].Equals("ln"))
                {
                    _levelName = line.Substring(3);
                }
                else if (split[0].Equals("ld"))
                {
                    _levelDesc = line.Substring(3);
                }
            }

            read.Close();

            string[] text = ReadInfo().Split('\n');

            foreach (string s in text)
            {
                string[] split = s.Split(' ');
                if (int.Parse(split[0]) == GameProperties.SelectedLevel)
                {
                    if (!split[1].Trim().Equals("-"))
                    {
                        double time = double.Parse(split[1].Trim());
                        if (time < _targetTimes[GameProperties.SelectedLevel - 1][0])
                        {
                            _pinNum = 0;
                        }
                        else if (time < _targetTimes[GameProperties.SelectedLevel - 1][1])
                        {
                            _pinNum = 1;
                        }
                        else if (time < _targetTimes[GameProperties.SelectedLevel - 1][2])
                        {
                            _pinNum = 2;
                        }
                        else
                        {
                            _pinNum = 3;
                        }
                    }
                    else
                    {
                        _pinNum = 4;
                    }
                    break;
                }
            }
            read.Close();

        }
        #endregion

        /// <summary>
        /// Loads all the target times that exist in the system.
        /// </summary>
        public static void LoadAllTargetTimes()
        {
            _targetTimes = new List<List<double>>();
            for (int i = 0; i < GameProperties.TOTAL_LEVELS; i++)
            {
                string path = GetLevelPath(i + 1);
                StreamReader read = new StreamReader(TitleContainer.OpenStream(path));

                try
                {
                    int numTimes = 0;
                    while (!read.EndOfStream)
                    {
                        string line = read.ReadLine();
                        string[] split = line.Split(' ');
                        if (numTimes > 4)
                            break;

                        if (split[0].Equals("t"))
                        {
                            _targetTimes.Add(new List<double>());
                            _targetTimes[i].Add(float.Parse(split[2]));
                            numTimes++;
                        }
                    }
                }
                finally
                {
                    read.Close();
                }

            }
        }

        /// <summary>
        /// Loads the pins of all levels from the save file.
        /// </summary>
        /// <returns></returns>
        public static List<int> LoadAllLevelRecords()
        {
            string[] text = ReadInfo().Split('\n');
            List<int> records = new List<int>();
            int i = 0;

            foreach (string s in text)
            {
                if (string.IsNullOrEmpty(s))
                {
                    break;
                }
                string[] split = s.Split(' ');

                if (!split[1].Trim().Equals("-"))
                {
                    double time = double.Parse(split[1].Trim());
                    if (time < _targetTimes[i][0])
                    {
                        records.Add(0);
                    }
                    else if (time < _targetTimes[i][1])
                    {
                        records.Add(1);
                    }
                    else if (time < _targetTimes[i][2])
                    {
                        records.Add(2);
                    }
                    else
                    {
                        records.Add(3);
                    }
                }
                else
                {
                    records.Add(4);
                }
                i++;
            }

            return records;

        }

        public static void RemoveObstaclesFromGestureManager()
        {
            foreach (Obstacle o in Obstacles)
            {
                if (o.GetType().Equals(typeof(Button)))
                {
                    ActionManager.RemoveTappableObject((Button)o);
                    ActionManager.RemovePullableObject((Button)o);
                }
                else if (o.GetType().Equals(typeof(Buckle)))
                {
                    ActionManager.RemovePinchableObject((Buckle)o);
                }
                else if (o.GetType().Equals(typeof(Velcro)))
                {
                    ActionManager.RemovePullableObject((Velcro)o);
                }
            }
        }

        private static string GetLevelPath()
        {
            string path = @"Content\Levels\level" + GameProperties.SelectedLevel + ".xlvl";

            return path;
        }

        private static string GetLevelPath(int levelNum)
        {
            string path = @"Content\Levels\level" + levelNum + ".xlvl";

            return path;
        }

        private static string GetLevelPath(int worldNum, int levelNum)
        {
            string path = @"Content\Levels\" + worldNum + @"\level" + levelNum + ".xlvl";

            return path;
        }

        private static void SetBG(int bgNum)
        {
            _background = SpriteManager.AddSprite(@"Content\Backgrounds\bg" + bgNum, "Global");
            _background.Z = -0.1f;
            float pixelsPerUnit = SpriteManager.Camera.PixelsPerUnitAt(_background.Z);
            _background.ScaleX = .5f * _background.Texture.Width / pixelsPerUnit;
            _background.ScaleY = .5f * _background.Texture.Height / pixelsPerUnit;
            _background.RotationZ = (float)Math.PI / 2;
        }

        public static void WipeScreen()
        {
            foreach (Obstacle g in _obstacles)
            {
                g.Destroy();
            }
            _obstacles.RemoveRange(0, _obstacles.Count);
            _track.RemoveRange(0, _track.Count);
            _targetTimes.RemoveRange(0, _track.Count);

            _zipper.Destroy();
            SpriteManager.RemoveSprite(_background);
        }
    }
}
